package com.wh.wisdomsite.xbox.utils.encrypt.rsa;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * RSAEncrypt加密和解密工具类
 * @author 谢泽鹏
 * @date 2014年10月13日 下午2:42:41
 * @Copyright 个人版权所有
 * @Company 贵州万华科技有限公司Copyright (c) 2014
 * @version V1.0
 */
public class RSA {

    private static final Log logger = LogFactory.getLog(RSA.class);
	
	public static final String DEFAULT_PUBLIC_KEY = 
		"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5C5yAQKD11ECHgjrjD8Rw8Hw1" + 
		"CNpwg5irhzSboXFwbFs/vyKz2ySY1ZovYu2hDBKq2ssOPuUPYkfZBAY5QbJ2/n/H" + 
		"oiiCKDpoInm0pqzOvdZYhMfP0tsLwKAIVADzCdi1tZPbPCfTzm+z0AgTt75w7wmO" + 
		"YM51uIx0ngLUwZN7EwIDAQAB";
	
	public static final String DEFAULT_PRIVATE_KEY =
			"MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALkLnIBAoPXUQIeC" + 
			"OuMPxHDwfDUI2nCDmKuHNJuhcXBsWz+/IrPbJJjVmi9i7aEMEqrayw4+5Q9iR9kE" + 
			"BjlBsnb+f8eiKIIoOmgiebSmrM691liEx8/S2wvAoAhUAPMJ2LW1k9s8J9POb7PQ" + 
			"CBO3vnDvCY5gznW4jHSeAtTBk3sTAgMBAAECgYBo9XoWkRH7fiH/+tFV+5qMCQwa" + 
			"tOPaD/qnyHABmqgSgZOca9jONY3jlrz3BeENiSCJgsLMWMZqXG+uW4cAMRB9UD83" + 
			"cX2nUv+nvCaZm+q45SNXV9vs7uxuzhfpS07V56zlkSZcqYvT9XVT3amrgqqHtGj8" + 
			"cUTNYDoqUr4wbcf42QJBAO+YRp32OK/YezC5C6cvWcnjRDUer/8Km4AVOQodtmTv" + 
			"VTAro8X/8QMwt8B4OwRXenW7YCKkBktHO0LYVlspL4cCQQDFtysQtXy1tz11U/Kz" + 
			"99CBhKeFMjZ40wlhrt2saHyOagFoiBUxoSvcK+8H+5oOj7kEZgmI7SHTu/KBlV4Y" + 
			"PAMVAkEA2zLfeGjpV8egfOTuylfBt7iakFaxAY580WOZOa4RTqq/r0BdpyoPH7IU" + 
			"ipv0snYt7UQuIcMalwhmKTOvXduCRQJBAKM3wM98Y0VHze6LrLIxA+nH7tsgRqOb" + 
			"5ATF7K2lXB3dGOiIXqan3KNXiW5XoCghMaWV7o0g5Wn7oAilnBX5hLkCQQC2xBBz" + 
			"kKEUQ6nBQ0uD1Vyj0FjSQWvc93FEP3bey4/X3sEaj2Edg3eC/dqnVTVd07d3IfbM" + 
			"yyojJ1+GFyE2Z/gJ";
	

	/**
	 * 私钥
	 */
	private RSAPrivateKey privateKey;

	/**
	 * 公钥
	 */
	private RSAPublicKey publicKey;
	
	/**
	 * 字节数据转字符串专用集合
	 */
	private static final char[] HEX_CHAR= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
	

	/**
	 * 获取私钥
	 * @return 当前的私钥对象
	 */
	public RSAPrivateKey getPrivateKey() {
		return privateKey;
	}

	/**
	 * 获取公钥
	 * @return 当前的公钥对象
	 */
	public RSAPublicKey getPublicKey() {
		return publicKey;
	}

	/**
	 * 随机生成密钥对
	 */
	public void genKeyPair(){
		KeyPairGenerator keyPairGen= null;
		try {
			keyPairGen = KeyPairGenerator.getInstance("RSA");
		}catch(NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		keyPairGen.initialize(1024, new SecureRandom());
		KeyPair keyPair= keyPairGen.generateKeyPair();
		this.privateKey= (RSAPrivateKey) keyPair.getPrivate();
		this.publicKey= (RSAPublicKey) keyPair.getPublic();
	}

	
	/**
	 * 从文件中输入流中加载公钥
	 * @param in 公钥输入流
	 * @throws Exception 加载公钥时产生的异常
	 */
	public void loadPublicKey(InputStream in) throws Exception{
		try {
			BufferedReader br= new BufferedReader(new InputStreamReader(in));
			String readLine= null;
			StringBuilder sb= new StringBuilder();
			while((readLine= br.readLine())!=null){
				if(readLine.charAt(0)=='-'){
					continue;
				}else{
					sb.append(readLine);
					sb.append('\r');
				}
			}
			loadPublicKey(sb.toString());
		} catch (IOException e) {
			logger.error("loadPublicKey(InputStream in)公钥数据流读取错误！" + e.getMessage());
			throw new Exception("公钥数据流读取错误");
		} catch (NullPointerException e) {
			logger.error("loadPublicKey(InputStream in)公钥输入流为空！" + e.getMessage());
			throw new Exception("公钥输入流为空");
		}
	}


	/**
	 * 从字符串中加载公钥
	 * @param publicKeyStr 公钥数据字符串
	 * @throws Exception 加载公钥时产生的异常
	 */
	public void loadPublicKey(String publicKeyStr) throws Exception{
		try {
			//Base64 base64Decoder= new Base64.;
			byte[] buffer = Base64.decode(publicKeyStr);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
			this.publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
		} catch (NoSuchAlgorithmException e) {
			logger.error("loadPublicKey(String publicKeyStr)无此算法！" + e.getMessage());
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			logger.error("loadPublicKey(String publicKeyStr)公钥非法！" + e.getMessage());
			throw new Exception("公钥非法");
		} catch (IOException e) {
			logger.error("loadPublicKey(String publicKeyStr)公钥数据内容读取错误！" + e.getMessage());
			throw new Exception("公钥数据内容读取错误");
		} catch (NullPointerException e) {
			logger.error("loadPublicKey(String publicKeyStr)公钥数据为空！" + e.getMessage());
			throw new Exception("公钥数据为空");
		}
	}
	

	/**
	 * 从文件中加载私钥
	 * @param in 私钥文件名
	 * @return 是否成功
	 * @throws Exception 
	 */
	public void loadPrivateKey(InputStream in) throws Exception{
		try {
			BufferedReader br= new BufferedReader(new InputStreamReader(in));
			String readLine= null;
			StringBuilder sb= new StringBuilder();
			while((readLine= br.readLine())!=null){
				if(readLine.charAt(0)=='-'){
					continue;
				}else{
					sb.append(readLine);
					sb.append('\r');
				}
			}
			loadPrivateKey(sb.toString());
		} catch (IOException e) {
			logger.error("loadPrivateKey(InputStream in)私钥数据读取错误！" + e.getMessage());
			throw new Exception("私钥数据读取错误");
		} catch (NullPointerException e) {
			logger.error("loadPrivateKey(InputStream in)私钥输入流为空！" + e.getMessage());
			throw new Exception("私钥输入流为空");
		}
	}

	
	public void loadPrivateKey(String privateKeyStr) throws Exception{
		try {
			//BASE64Decoder base64Decoder= new BASE64Decoder();
			byte[] buffer= Base64.decode(privateKeyStr);
			PKCS8EncodedKeySpec keySpec= new PKCS8EncodedKeySpec(buffer);
			KeyFactory keyFactory= KeyFactory.getInstance("RSA");
			this.privateKey= (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (NoSuchAlgorithmException e) {
			logger.error("loadPrivateKey(String privateKeyStr)无此算法！" + e.getMessage());
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			logger.error("loadPrivateKey(String privateKeyStr)私钥非法！" + e.getMessage());
			throw new Exception("私钥非法");
		} catch (IOException e) {
			logger.error("loadPrivateKey(String privateKeyStr)私钥数据内容读取错误！" + e.getMessage());
			throw new Exception("私钥数据内容读取错误");
		} catch (NullPointerException e) {
			logger.error("loadPrivateKey(String privateKeyStr)私钥数据为空！" + e.getMessage());
			throw new Exception("私钥数据为空");
		}
	}

	/**
	 * 加密过程
	 * @param publicKey 公钥
	 * @param data 明文数据
	 * @return
	 * @throws Exception 加密过程中的异常信息
	 */
	public byte[] encrypt(RSAPublicKey publicKey, byte[] data) throws Exception{
		if(publicKey== null){
			logger.info("encrypt(RSAPublicKey publicKey, byte[] data)加密公钥为空, 请设置！");
			throw new Exception("加密公钥为空, 请设置");
		}
		Cipher cipher= null;
		try {
			cipher= Cipher.getInstance("RSA/None/OAEPPadding", new BouncyCastleProvider());
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			//byte[] output= cipher.doFinal(plainTextData);
			int blockSize = cipher.getBlockSize();// 获得加密块大小，如：加密前数据为128个byte，而key_size=1024
			// 加密块大小为127
			// byte,加密后为128个byte;因此共有2个加密块，第一个127
			// byte第二个为1个byte
			int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
			int leavedSize = data.length % blockSize;
			int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
					: data.length / blockSize;
			byte[] raw = new byte[outputSize * blocksSize];
			int i = 0;
			while (data.length - i * blockSize > 0) {
				if (data.length - i * blockSize > blockSize)
					cipher.doFinal(data, i * blockSize, blockSize, raw, i
							* outputSize);
				else
					cipher.doFinal(data, i * blockSize, data.length - i
							* blockSize, raw, i * outputSize);
				i++;
			}
			return raw;
		} catch (NoSuchAlgorithmException e) {
			logger.error("encrypt(RSAPublicKey publicKey, byte[] data)无此加密算法！" + e.getMessage());
			throw new Exception("无此加密算法");
		} catch (NoSuchPaddingException e) {
			logger.error("encrypt(RSAPublicKey publicKey, byte[] data)加密有误！" + e.getMessage());
			throw new Exception("加密有误");
		}catch (InvalidKeyException e) {
			logger.error("encrypt(RSAPublicKey publicKey, byte[] data)加密公钥非法,请检查！" + e.getMessage());
			throw new Exception("加密公钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			logger.error("encrypt(RSAPublicKey publicKey, byte[] data)明文长度非法！" + e.getMessage());
			throw new Exception("明文长度非法");
		} catch (BadPaddingException e) {
			logger.error("encrypt(RSAPublicKey publicKey, byte[] data)明文数据已损坏！" + e.getMessage());
			throw new Exception("明文数据已损坏");
		}
	}
	
	/**
	 * 私钥加密
	 * @param privateKey
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public byte[] encrypt(RSAPrivateKey privateKey, byte[] data) throws Exception{
		if(publicKey== null){
			throw new Exception("加密私钥为空, 请设置");
		}
		Cipher cipher= null;
		try {
			cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
			cipher.init(Cipher.ENCRYPT_MODE, privateKey);
			//byte[] output= cipher.doFinal(plainTextData);
			int blockSize = cipher.getBlockSize();// 获得加密块大小，如：加密前数据为128个byte，而key_size=1024
			// 加密块大小为127
			// byte,加密后为128个byte;因此共有2个加密块，第一个127
			// byte第二个为1个byte
			int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
			int leavedSize = data.length % blockSize;
			int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
					: data.length / blockSize;
			byte[] raw = new byte[outputSize * blocksSize];
			int i = 0;
			while (data.length - i * blockSize > 0) {
				if (data.length - i * blockSize > blockSize)
					cipher.doFinal(data, i * blockSize, blockSize, raw, i
							* outputSize);
				else
					cipher.doFinal(data, i * blockSize, data.length - i
							* blockSize, raw, i * outputSize);
				i++;
			}
			return raw;
		} catch (Exception e) {
			logger.error("encrypt(RSAPrivateKey privateKey, byte[] data)无此加密算法！" + e.getMessage());
			throw new Exception("无此加密算法");
		} 
	}


	/**
	 * 解密过程
	 * @param publicKey 公钥
	 * @param cipherData 密文数据
	 * @return 明文
	 * @throws Exception 解密过程中的异常信息
	 */
	public byte[] decrypt(RSAPublicKey publicKey, byte[] cipherData) throws Exception{
		if (privateKey== null){
			throw new Exception("解密公钥为空, 请设置");
		}
		Cipher cipher= null;
		try {
			cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
			cipher.init(Cipher.DECRYPT_MODE, publicKey);

			int blockSize = cipher.getBlockSize();
			ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
			int j = 0;

			while (cipherData.length - j * blockSize > 0) {
				bout.write(cipher.doFinal(cipherData, j * blockSize, blockSize));
				j++;
			}
			return bout.toByteArray();
		} catch (Exception e) {
			logger.error("decrypt(RSAPublicKey publicKey, byte[] cipherData)无此解密算法！" + e.getMessage());
			throw new Exception("无此解密算法");
		}	
	}

	/**
	 * 解密过程
	 * @param privateKey 私钥
	 * @param cipherData 密文数据
	 * @return 明文
	 * @throws Exception 解密过程中的异常信息
	 */
	public byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception{
		if (privateKey== null){
			throw new Exception("解密私钥为空, 请设置");
		}
		Cipher cipher= null;
		try {
			cipher= Cipher.getInstance("RSA/None/OAEPPadding", new BouncyCastleProvider());
			cipher.init(Cipher.DECRYPT_MODE, privateKey);

			int blockSize = cipher.getBlockSize();
			ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
			int j = 0;

			while (cipherData.length - j * blockSize > 0) {
				bout.write(cipher.doFinal(cipherData, j * blockSize, blockSize));
				j++;
			}
			return bout.toByteArray();
		} catch (NoSuchAlgorithmException e) {
			logger.error("decrypt(RSAPrivateKey privateKey, byte[] cipherData)无此解密算法！" + e.getMessage());
			throw new Exception("无此解密算法");
		} catch (InvalidKeyException e) {
			logger.error("decrypt(RSAPrivateKey privateKey, byte[] cipherData)解密私钥非法,请检查！" + e.getMessage());
			throw new Exception("解密私钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			logger.error("decrypt(RSAPrivateKey privateKey, byte[] cipherData)密文长度非法！" + e.getMessage());
			throw new Exception("密文长度非法");
		} catch (BadPaddingException e) {
			logger.error("decrypt(RSAPrivateKey privateKey, byte[] cipherData)密文数据已损坏！" + e.getMessage());
			throw new Exception("密文数据已损坏");
			
		}		
	}
	
	/**
	 * 字节数据转十六进制字符串
	 * @param data 输入数据
	 * @return 十六进制内容
	 */
	public static String byteArrayToString(byte[] data){
		StringBuilder stringBuilder= new StringBuilder();
		for (int i=0; i<data.length; i++){
			//取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
			stringBuilder.append(HEX_CHAR[(data[i] & 0xf0)>>> 4]);
			//取出字节的低四位 作为索引得到相应的十六进制标识符
			stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
			if (i<data.length-1){
				stringBuilder.append(' ');
			}
		}
		return stringBuilder.toString();
	}


	
	
	/**
	 * 通过公钥加密文本
	 * @param encrypStr 加密文本
	 * @return String   加密值
	 */
	public static String rSAEncrypt_PUBLICKEY_encrypt(String encrypStr){
        String encryptString = null;
		try {
            logger.info("rSAEncrypt_PUBLICKEY_encrypt->>通过公钥加密文本");
            logger.info("rSAEncrypt_PUBLICKEY_encrypt->>加密源: " + encrypStr);
			RSA rsaEncrypt = new RSA();
			rsaEncrypt.loadPrivateKey(RSA.DEFAULT_PRIVATE_KEY);
			rsaEncrypt.loadPublicKey(RSA.DEFAULT_PUBLIC_KEY);
			byte[] cipher = rsaEncrypt.encrypt(rsaEncrypt.getPublicKey(), encrypStr.getBytes());
            encryptString = HexBin.encode(cipher);
            logger.info("rSAEncrypt_PUBLICKEY_encrypt->>加密值: " + encryptString);
		} catch (Exception e) {
			e.printStackTrace();
            encryptString = null;
			logger.error("rSAEncrypt_PUBLICKEY_encrypt->>Exception " + e.getMessage());
		}
            return encryptString;
	}
	
	
	/**
	 * 通过公钥解密文本
	 * @param encrypStr 解密文本
	 * @return String   解密值
	 */
	public static String rSAEncrypt_PUBLICKEY_decrypt(String encrypStr){
        String decryptString = null;
		try {
            logger.info("rSAEncrypt_PUBLICKEY_decrypt->>通过公钥解密文本");
            logger.info("rSAEncrypt_PUBLICKEY_decrypt->>解密源：" + encrypStr);
			RSA rsaEncrypt = new RSA();
			rsaEncrypt.loadPublicKey(RSA.DEFAULT_PUBLIC_KEY);
			rsaEncrypt.loadPrivateKey(RSA.DEFAULT_PRIVATE_KEY);
			byte[] plainText = rsaEncrypt.decrypt(rsaEncrypt.getPublicKey(), HexBin.decode(encrypStr));
            decryptString = new String(plainText);
            logger.info("rSAEncrypt_PUBLICKEY_decrypt->>解密值：" + decryptString);
		} catch (Exception e) {
			e.printStackTrace();
            decryptString = null;
			logger.error("rSAEncrypt_PUBLICKEY_decrypt->>Exception " + e.getMessage());
		}
            return decryptString;
	}
	
	
	/**
	 * 通过私钥加密文本
	 * @param encryptStr 加密文本
	 * @return String   加密值
	 */
	public static String rSAEncrypt_PRIVATE_encrypt(String encryptStr){
        String encryptString = null;
		try {
            logger.info("rSAEncrypt_PRIVATE_encrypt->>通过私钥加密文本");
            logger.info("rSAEncrypt_PRIVATE_encrypt->>加密源: " + encryptStr);
			RSA rsaEncrypt = new RSA();
			rsaEncrypt.loadPrivateKey(RSA.DEFAULT_PRIVATE_KEY);
			rsaEncrypt.loadPublicKey(RSA.DEFAULT_PUBLIC_KEY);
			byte[] cipher = rsaEncrypt.encrypt(rsaEncrypt.getPrivateKey(), encryptStr.getBytes());
            encryptString = HexBin.encode(cipher);
            logger.info("rSAEncrypt_PRIVATE_encrypt->>加密值: " + encryptString);
		} catch (Exception e) {
			e.printStackTrace();
            encryptString = null;
			logger.error("rSAEncrypt_PRIVATE_encrypt->>Exception " + e.getMessage());
		}
            return encryptString;
	}
	
	
	
	
	/**
	 * 通过私钥解密文本
	 * @param decryptStr 解密文本
	 * @return String   解密值
	 */
	public static String rSAEncrypt_PRIVATE_decrypt(String decryptStr){
        String decryptString = null;
		try {
            logger.info("rSAEncrypt_PRIVATE_decrypt->>通过私钥解密文本");
			RSA rsaEncrypt = new RSA();
			rsaEncrypt.loadPrivateKey(RSA.DEFAULT_PRIVATE_KEY);
			rsaEncrypt.loadPublicKey(RSA.DEFAULT_PUBLIC_KEY);
			byte[] plainText = rsaEncrypt.decrypt(rsaEncrypt.getPrivateKey(), HexBin.decode(decryptStr));
            decryptString = new String(plainText,"UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
            decryptString = null;
			logger.error("rSAEncrypt_PRIVATE_decrypt->>Exception " + e.getMessage());
		}
            return decryptString;
	}


    public static void main(String[] args) throws Exception {
        String ssrc = "第三方第十四大幅度";

        //方式1(私钥加密, 公钥解密)
//        String encrypt_str = RSA.rSAEncrypt_PRIVATE_encrypt(ssrc);
//        RSA.rSAEncrypt_PUBLICKEY_decrypt(encrypt_str);

        //方式2(公钥加密, 私钥解密)
        String encrypt_str = RSA.rSAEncrypt_PUBLICKEY_encrypt(ssrc);
       // RSA.rSAEncrypt_PRIVATE_decrypt(encrypt_str);



    }



    }